﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace FRAFV.Common
{
	public interface IKeyItem<TKey, TValue>
	{
		TKey Key { get; }
		TValue Value { get; set; }
	}

	public class KeyCollection<TKey, TItem>: ICollection<TItem>
	{
		protected IList<TItem> items = new List<TItem>();

		protected virtual bool Equals(ref TItem item, TKey key)
		{
			IEquatable<TKey> eq = item as IEquatable<TKey>;
			if (eq != null)
				return eq.Equals(key);
			return System.Object.Equals(item, key);
		}

		protected virtual int IndexOf(TKey key)
		{
			for (int k = 0; k < this.items.Count; k++)
			{
				var item = this.items[k];
				if (Equals(ref item, key))
					return k;
			}
			return -1;
		}

		public void Clear()
		{
			this.items.Clear();
		}

		public bool Contains(TKey key)
		{
			return IndexOf(key) >= 0;
		}

		public int Count
		{
			get { return this.items.Count; }
		}

		public virtual TItem GetItem(int index)
		{
			return this.items[index];
		}

		public virtual bool Remove(TKey key)
		{
			return Remove(key, false);
		}

		protected bool Remove(TKey key, bool each)
		{
			bool res = false;
			if (each)
			{
				int k = IndexOf(key);
				res = k >= 0;
				if (res) this.items.RemoveAt(k);
			}
			else
			{
				for (int k = this.items.Count - 1; k >= 0; k--)
				{
					var item = this.items[k];
					if (Equals(ref item, key))
					{
						this.items.RemoveAt(k);
						res = true;
					}
				}
			}
			return res;
		}

		public void RemoveAt(int index)
		{
			this.items.RemoveAt(index);
		}

		public virtual void SetItem(int index, TItem item)
		{
			this.items[index] = item;
		}

		void ICollection<TItem>.Add(TItem item)
		{
			this.items.Add(item);
		}

		bool ICollection<TItem>.Contains(TItem item)
		{
			return this.items.Contains(item);
		}

		void ICollection<TItem>.CopyTo(TItem[] array, int arrayIndex)
		{
			this.items.CopyTo(array, arrayIndex);
		}

		bool ICollection<TItem>.IsReadOnly
		{
			get { return false; }
		}

		bool ICollection<TItem>.Remove(TItem item)
		{
			return this.items.Remove(item);
		}

		IEnumerator<TItem> IEnumerable<TItem>.GetEnumerator()
		{
			return this.items.GetEnumerator();
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return this.items.GetEnumerator();
		}
	}

	public class KeyCollection<TKey, TValue, TItem>: KeyCollection<TKey, TItem>
		where TItem: IKeyItem<TKey, TValue>
	{
		protected virtual TItem CreateValue(TKey key, TValue value)
		{
			return (TItem)Activator.CreateInstance(typeof(TItem), key, value);
		}

		protected override bool Equals(ref TItem item, TKey key)
		{
			IEquatable<TKey> eq = item.Key as IEquatable<TKey>;
			if (eq != null)
				return eq.Equals(key);
			return System.Object.Equals(item.Key, key);
		}

		public TValue this[TKey key]
		{
			get
			{
				return GetValue(IndexOf(key));
			}
			set
			{
				SetValue(IndexOf(key), key, value);
			}
		}

		public void Add(TKey key, TValue value)
		{
			this.items.Add(CreateValue(key, value));
		}

		public virtual TKey GetKey(int index)
		{
			if (index >= 0 && index < this.items.Count)
				return this.items[index].Key;
			else
				return default(TKey);
		}

		public virtual TValue GetValue(int index)
		{
			if (index >= 0 && index < this.items.Count)
				return this.items[index].Value;
			else
				return default(TValue);
		}

		public void Insert(int index, TKey key, TValue value)
		{
			this.items.Insert(index, CreateValue(key, value));
		}

		public virtual void SetValue(int index, TKey key, TValue value)
		{
			if (index >= 0 && index < this.items.Count)
			{
				var item = this.items[index];
				if (!Equals(ref item, key))
					throw new ArgumentOutOfRangeException("key");
				item.Value = value;
				this.items[index] = item;
			}
			else
				this.items.Add(CreateValue(key, value));
		}
	}
}
